package com.jzo2o.health.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.trade.RefundRecordApi;
import com.jzo2o.api.trade.dto.response.ExecutionResultResDTO;
import com.jzo2o.api.trade.enums.RefundStatusEnum;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.mapper.OrdersMapper;
import com.jzo2o.health.model.UserThreadLocal;
import com.jzo2o.health.model.domain.Orders;
import com.jzo2o.health.model.domain.OrdersCancelled;
import com.jzo2o.health.model.domain.OrdersRefund;
import com.jzo2o.health.model.dto.OrderCanelDTO;
import com.jzo2o.health.model.dto.request.OrdersCancelReqDTO;
import com.jzo2o.health.service.IOrderCanceledService;
import com.jzo2o.health.service.IOrdersManagerService;
import com.jzo2o.health.service.IOrdersRefundService;
import com.jzo2o.mvc.utils.UserContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@Service
public class OrdersManagerServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersManagerService {

    @Resource
    private IOrdersManagerService currentProxy;

    @Resource
    private IOrderCanceledService orderCanceledService;

    @Resource
    private IOrdersRefundService ordersRefundService;

    @Resource
    private RefundRecordApi refundRecordApi;

    @Override
    public void cancel(OrdersCancelReqDTO dto) {

        Long memberId = UserThreadLocal.currentUserId();
        Integer userType = UserThreadLocal.currentUser().getUserType();
        String name = UserThreadLocal.currentUser().getName();
        //1.查询订单
        Orders orders = getById(dto.getId());
        if (orders == null) {
            throw new BadRequestException("订单不存在");
        }

        //准备参数
        OrderCanelDTO orderCanelDTO = new OrderCanelDTO();
        orderCanelDTO.setId(dto.getId());
        orderCanelDTO.setCancellerId(memberId);
        orderCanelDTO.setCancellerName(name);
        orderCanelDTO.setCancellerType(userType);
        orderCanelDTO.setCancelReason(dto.getCancelReason());

        //2.判断订单状态
        if (ObjectUtils.equal(orders.getOrderStatus(), OrderStatusEnum.NO_PAY.getStatus())) {
            //取消未支付的订单
            currentProxy.cancelNoPayOrder(orderCanelDTO);
        }
        else {
            throw new BadRequestException("状态不对");
        }

    }

    @Override
    public void requestRefundOrder(Long id, BigDecimal setmealPrice, Long tradingOrderNo) {
        //1. 通过trade服务发起退款申请，得到退款操作的结果
        ExecutionResultResDTO res = refundRecordApi.refundTrading(tradingOrderNo, setmealPrice);
        //2. 处理退款的结果
        currentProxy.refundOrder(res, id);
    }

    @Override
    public void refundOrder(ExecutionResultResDTO res, Long id) {
        //1. 获取退款状态。这个状态是trade服务里状态值
        Integer refundStatus = res.getRefundStatus();
        //2. 判断退款的状态，如果是退款中状态，就直接结束
        if (ObjectUtils.equal(refundStatus, RefundStatusEnum.SENDING.getCode())) {
            return;
        }
        //3. 如果不是退款中，就需要完成退款后的处理
        //3.1 将trade服务返回的结果状态，转换成Orders表里自己枚举对应的状态
        if (ObjectUtils.equal(refundStatus, RefundStatusEnum.SUCCESS.getCode())) {
            refundStatus = OrderPayStatusEnum.REFUND_SUCCESS.getStatus();
        } else if (ObjectUtils.equal(refundStatus, RefundStatusEnum.FAIL.getCode())) {
            refundStatus = OrderPayStatusEnum.REFUND_FAIL.getStatus();
        }
        //3.2 修改orders表的状态
        boolean updated = lambdaUpdate()
                .set(Orders::getPayStatus, refundStatus)
                .set(Orders::getRefundNo, res.getRefundNo())
                .set(Orders::getRefundId, res.getRefundId())
                .eq(Orders::getId, id)
                .update();
        if (updated) {
            //3.3 删除待退款记录
            ordersRefundService.removeById(id);
        }
    }

    @Override
    public List<Orders> queryOverTimeNoPayOrdersByCount(int count) {
        return lambdaQuery()
                .eq(Orders::getOrderStatus, OrderStatusEnum.NO_PAY.getStatus())
                .lt(Orders::getCreateTime, LocalDateTime.now().minusMonths(15))
                //在SQL语句最后拼接上，limit数量
                .last("limit" + count)
                .list();
    }

    @Override
    public void abc(OrdersCancelReqDTO ordersCancelReqDTO) {

        Long memberId = UserThreadLocal.currentUserId();
        Integer userType = UserThreadLocal.currentUser().getUserType();
        String name = UserThreadLocal.currentUser().getName();

        //1.查询订单
        Orders orders = getById(ordersCancelReqDTO.getId());
        if (orders == null) {
            throw new BadRequestException("订单不存在");
        }

        //准备参数
        OrderCanelDTO orderCanelDTO = new OrderCanelDTO();
        orderCanelDTO.setId(ordersCancelReqDTO.getId());
        orderCanelDTO.setCancellerId(memberId);
        orderCanelDTO.setCancellerName(name);
        orderCanelDTO.setCancellerType(userType);
        orderCanelDTO.setCancelReason(ordersCancelReqDTO.getCancelReason());

        if (ObjectUtils.equal(orders.getOrderStatus(), OrderStatusEnum.WAITING_CHECKUP.getStatus())) {
            //准备数据：交易单id 和 退款金额
            orderCanelDTO.setTradingOrderNo(orders.getTradingOrderNo());
            orderCanelDTO.setSetmealPrice(orders.getSetmealPrice());
            currentProxy.cancelDispatchingOrder(orderCanelDTO);
            //申请退款：为防止取消派单中订单执行流程过长、耗时太久，用户体验不好，我们申请退款使用异步（采用线程方式）
            new Thread(() -> {
                requestRefundOrder(orders.getId(), orders.getSetmealPrice(), orders.getTradingOrderNo());
            }).start();
        }else {
            throw new BadRequestException("状态不对");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelNoPayOrder(OrderCanelDTO orderCanelDTO) {
        //1.修改订单状态
        lambdaUpdate()
                .set(Orders::getOrderStatus, OrderStatusEnum.CANCELLED.getStatus())
                .eq(Orders::getId, orderCanelDTO.getId())
                .update();
        //2.新增一条订单取消记录
        OrdersCancelled ordersCancelled = new OrdersCancelled();
        ordersCancelled.setId(orderCanelDTO.getId());
        ordersCancelled.setCancellerId(orderCanelDTO.getCancellerId());
        ordersCancelled.setCancellerName(orderCanelDTO.getCancellerName());
        ordersCancelled.setCancellerType(orderCanelDTO.getCancellerType());
        ordersCancelled.setCancelReason(orderCanelDTO.getCancelReason());
        ordersCancelled.setCancelTime(LocalDateTime.now());
        orderCanceledService.save(ordersCancelled);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelDispatchingOrder(OrderCanelDTO orderCanelDTO) {
        //1.修改订单表的状态，关闭状态，退款中
        boolean updated = lambdaUpdate()
                .set(Orders::getOrderStatus, OrderStatusEnum.CLOSED.getStatus())
                .set(Orders::getPayStatus, OrderPayStatusEnum.REFUNDING.getStatus())
                .eq(Orders::getId, orderCanelDTO.getId())
                .update();
        if (!updated) {
            throw new CommonException("订单不存在");
        }
        //2.新增一条取消记录
        OrdersCancelled ordersCancelled = new OrdersCancelled();
        ordersCancelled.setId(orderCanelDTO.getId());
        ordersCancelled.setCancellerId(orderCanelDTO.getCancellerId());
        ordersCancelled.setCancellerName(orderCanelDTO.getCancellerName());
        ordersCancelled.setCancellerType(orderCanelDTO.getCancellerType());
        ordersCancelled.setCancelReason(orderCanelDTO.getCancelReason());
        ordersCancelled.setCancelTime(LocalDateTime.now());
        orderCanceledService.save(ordersCancelled);
        //3.新增一条退款记录
        OrdersRefund ordersRefund = new OrdersRefund();
        ordersRefund.setId(orderCanelDTO.getId());
        ordersRefund.setTradingOrderNo(orderCanelDTO.getTradingOrderNo());
        ordersRefund.setRealPayAmount(orderCanelDTO.getSetmealPrice());
        ordersRefund.setCreateTime(LocalDateTime.now());
        ordersRefundService.save(ordersRefund);
    }
}




















